package com.moyuwanjia.Factory;

import com.moyuwanjia.service.IAccountService;
import com.moyuwanjia.utils.TransactionManager;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author 摸鱼丸加~
 * @create 2022-07-11 13:52
 * 用于创建Service的代理对象的工厂
 */
public class BeanFactory {
    private IAccountService iAccountService;
    private TransactionManager transactionManager;

    /**
     * 注入transactionMamager方法
     * @param transactionManager
     * 当匿名内部类访问外部成员变量时，外部成员要求是最终的，所以使用final修饰
     * 但是这里是使用set方法注入，所以将final修饰符放在方法上
     */
    public final void setTransactionManager(TransactionManager transactionManager){
        this.transactionManager = transactionManager;
    }
    /**
     * 注入service对象
     * @param iAccountService
     */
    public void setIAccountService(IAccountService iAccountService){
        this.iAccountService = iAccountService;
    }

    /**
     * @return 代理的service对象
     */
    public IAccountService getIAccountService(){
        return (IAccountService) Proxy.newProxyInstance(iAccountService.getClass().getClassLoader()
                , iAccountService.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 匿名内部类
                     * @param proxy
                     * @param method
                     * @param args
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代理执行");
                        Object returnValue = null;
                        try {
                            transactionManager.beginTransaction();
                            returnValue = method.invoke(iAccountService, args);
                            transactionManager.commit();
                            return returnValue;
                        } catch (Exception e) {
                            transactionManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
                            transactionManager.release();
                        }
                    }
                }
        );
    }
}
